﻿// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System.Collections.Generic;

namespace Nova.UI
{
    /// <summary>
    /// Used to manage collections of child <see cref="CodeObjectVM"/>s, setting the Parent of
    /// each child object added to the collection.
    /// </summary>
    /// <typeparam name="T">The specific type of objects in the collection (must be <see cref="CodeObjectVM"/> or a derived type).</typeparam>
    public class ChildListVM<T> : List<T> where T : CodeObjectVM
    {
        #region /* FIELDS */

        protected CodeObjectVM ParentVM;

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a <see cref="ChildListVM{T}"/>, optionally using a specified parent <see cref="CodeObjectVM"/> object.
        /// </summary>
        public ChildListVM(CodeObjectVM parentVM)
        {
            ParentVM = parentVM;
        }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The Parent object of the collection.
        /// </summary>
        public CodeObjectVM Parent
        {
            get { return ParentVM; }
        }

        /// <summary>
        /// Get the last item in the collection.
        /// </summary>
        public T Last
        {
            get { return (Count > 0 ? this[Count - 1] : null); }
        }

        #endregion

        #region /* METHODS */

        /// <summary>
        /// Add an item to the collection, setting its Parent.
        /// </summary>
        public new void Add(T item)
        {
            if (item != null)
            {
                //// If any added items already have a parent, and it's not the same as the parent of this collection,
                //// clone them so that we don't end up changing their Parent.  Otherwise, this could happen in many cases,
                //// such as adding an evaluated TypeRef as a type argument, etc.  If code objects are moved (such as drag/drop),
                //// they will be removed first, which will null the Parent reference, then added, avoiding the clone.
                //if (item.Parent != null && item.Parent != ParentVM)
                //    item = (T)item.Clone();
                item.ParentVM = ParentVM;
            }
            base.Add(item);
        }

        /// <summary>
        /// Add a collection of items to the collection, setting their Parents.
        /// </summary>
        public new void AddRange(IEnumerable<T> collection)
        {
            if (collection != null)
            {
                foreach (T item in collection)
                    Add(item);
            }
        }

        /// <summary>
        /// Insert an item into the collection, setting its Parent.
        /// </summary>
        public new void Insert(int index, T item)
        {
            base.Insert(index, item);
            if (item != null)
                item.ParentVM = ParentVM;
        }

        #endregion
    }

    #region /* STATIC HELPER METHODS */

    /// <summary>
    /// Static helper methods for ChildList - used in these cases so that the collection itself can be
    /// checked for being null inside the call.
    /// </summary>
    public static class ChildListHelpers
    {
        /// <summary>
        /// Return the first object in the collection, or null if the collection is null or empty.
        /// </summary>
        public static T First<T>(ChildListVM<T> thisChildList) where T : CodeObjectVM
        {
            return ((thisChildList != null && thisChildList.Count > 0) ? thisChildList[0] : null);
        }

        public static void UnRender<T>(ChildListVM<T> thisChildList) where T : CodeObjectVM
        {
            if (thisChildList != null)
            {
                foreach (T codeObjectVM in thisChildList)
                {
                    if (codeObjectVM != null)
                        codeObjectVM.UnRender();
                }
            }
        }
    }

    #endregion
}
